require 'xcjobs'
require 'json'

def xcode_version
  `xcodebuild -version`.split("\n").first.scan(/\d+/).join('.')
end

def destinations(platform: 'iphonesimulator')
  if platform == 'iphonesimulator'
    if xcode_version.start_with?('11')
      [ 'name=iPhone 11 Pro,OS=13.0'
      ]
    elsif xcode_version.start_with?('10')
      [ 'name=iPhone 5s,OS=12.0',
        'name=iPhone 6,OS=12.0',
        'name=iPhone 6s Plus,OS=12.0',
        'name=iPhone SE,OS=12.0',
        'name=iPad Air 2,OS=12.0',
        'name=iPad Pro (9.7-inch),OS=12.0',
        'name=iPad Pro (12.9-inch),OS=12.0'
      ]
    elsif xcode_version.start_with?('9.4')
      [ 'name=iPhone 5s,OS=11.4',
        'name=iPhone 6,OS=11.4',
        'name=iPhone 6s Plus,OS=11.4',
        'name=iPhone SE,OS=11.4',
        'name=iPad Air 2,OS=11.4',
        'name=iPad Pro (9.7-inch),OS=11.4',
        'name=iPad Pro (12.9-inch),OS=11.4'
      ]
    elsif xcode_version.start_with?('9.3')
      [ 'name=iPhone 5s,OS=11.0.1',
        'name=iPhone 5s,OS=11.1',
        'name=iPhone 6,OS=11.2',
        'name=iPhone 6s Plus,OS=11.3',
        'name=iPhone SE,OS=11.0.1',
        'name=iPad Air 2,OS=11.1',
        'name=iPad Pro (9.7-inch),OS=11.2',
        'name=iPad Pro (12.9-inch),OS=11.3'
      ]
    elsif xcode_version.start_with?('9.2')
      [ 'name=iPhone 5s,OS=11.2',
        'name=iPhone 5s,OS=11.2',
        'name=iPhone 6,OS=11.2',
        'name=iPhone 6s Plus,OS=11.2',
        'name=iPhone SE,OS=11.2',
        'name=iPad Air 2,OS=11.2',
        'name=iPad Pro (9.7-inch),OS=11.2',
        'name=iPad Pro (12.9-inch),OS=11.2'
      ]
    elsif xcode_version.start_with?('9.1')
      [ 'name=iPhone 5s,OS=11.1',
        'name=iPhone 5s,OS=11.1',
        'name=iPhone 6,OS=11.1',
        'name=iPhone 6s Plus,OS=11.1',
        'name=iPhone SE,OS=11.1',
        'name=iPad Air 2,OS=11.1',
        'name=iPad Pro (9.7-inch),OS=11.1',
        'name=iPad Pro (12.9-inch),OS=11.1'
      ]
    elsif xcode_version.start_with?('9')
      [ 'name=iPhone 5,OS=10.0',
        'name=iPhone 5s,OS=10.0',
        'name=iPhone 6,OS=10.0',
        'name=iPhone 6s Plus,OS=10.3.1',
        'name=iPhone SE,OS=10.3.1',
        'name=iPhone 7,OS=11.0',
        'name=iPad Air 2,OS=10.0',
        'name=iPad Pro (9.7-inch),OS=10.0',
        'name=iPad Pro (12.9-inch),OS=10.0',
        'name=iPad Pro (10.5-inch),OS=11.0'
      ]
    else
      [ 'name=iPhone 5,OS=10.0',
        'name=iPhone 5s,OS=10.0',
        'name=iPhone 6,OS=10.0',
        'name=iPhone 6s Plus,OS=10.3.1',
        'name=iPhone SE,OS=10.3.1',
        'name=iPad Air 2,OS=10.0',
        'name=iPad Pro (9.7-inch),OS=10.0',
        'name=iPad Pro (12.9-inch),OS=10.0'
      ]
    end
  elsif platform == 'watchsimulator'
    if xcode_version.start_with?('11')
      [ 'name=Apple Watch Series 4 - 44mm,OS=6.0'
      ]
    elsif xcode_version.start_with?('10')
      [ 'name=Apple Watch Series 4 - 40mm,OS=5.0',
        'name=Apple Watch Series 4 - 44mm,OS=5.0'
      ]
    elsif xcode_version.start_with?('9.4')
      [ 'name=Apple Watch Series 3 - 38mm,OS=4.3',
        'name=Apple Watch Series 3 - 42mm,OS=4.3'
      ]
    elsif xcode_version.start_with?('9.3')
      [ 'name=Apple Watch - 38mm,OS=4.3',
        'name=Apple Watch - 42mm,OS=4.3',
        'name=Apple Watch Series 2 - 42mm,OS=4.3'
      ]
    elsif xcode_version.start_with?('9.2')
      [ 'name=Apple Watch - 38mm,OS=4.2',
        'name=Apple Watch - 42mm,OS=4.2',
        'name=Apple Watch Series 2 - 42mm,OS=4.2'
      ]
    elsif xcode_version.start_with?('9.1')
      [ 'name=Apple Watch - 38mm,OS=4.1',
        'name=Apple Watch - 42mm,OS=4.1',
        'name=Apple Watch Series 2 - 42mm,OS=4.1'
      ]
    elsif xcode_version.start_with?('9')
      [ 'name=Apple Watch - 38mm,OS=3.2',
        'name=Apple Watch - 42mm,OS=4.0',
        'name=Apple Watch Series 2 - 42mm,OS=4.0'
      ]
    else
      [ 'name=Apple Watch - 38mm,OS=3.2',
        'name=Apple Watch Series 2 - 42mm,OS=3.2'
      ]
    end
  elsif platform == 'appletvsimulator'
    if xcode_version.start_with?('11')
      [ 'name=Apple TV 4K,OS=13.0'
      ]
    elsif xcode_version.start_with?('10')
      [ 'name=Apple TV 4K,OS=12.0'
      ]
    elsif xcode_version.start_with?('9.4')
      [ 'name=Apple TV 4K,OS=11.4'
      ]
    elsif xcode_version.start_with?('9.3')
      [ 'name=Apple TV 4K,OS=11.3'
      ]
    elsif xcode_version.start_with?('9.2')
      [ 'name=Apple TV 4K,OS=11.2'
      ]
    elsif xcode_version.start_with?('9.1')
      [ 'name=Apple TV 4K,OS=11.1'
      ]
    elsif xcode_version.start_with?('9')
      [ 'name=Apple TV 1080p,OS=10.2',
        'name=Apple TV 1080p,OS=11.0'
      ]
    else
      [ 'name=Apple TV 1080p,OS=10.2'
      ]
    end
  else
    [
      'platform=OS X,arch=x86_64'
    ]
  end
end

def supportedPlatforms
  ['macosx', 'iphoneos', 'iphonesimulator', 'watchos', 'watchsimulator', 'appletvos', 'appletvsimulator']
end

def configurations
  ['Debug', 'Release']
end

desc "build for all platforms"
task :build do |t|
  supportedPlatforms
    .product(configurations)
    .map { |platform, configuration| Rake::Task["build:#{platform}:#{configuration.downcase}"] }
    .map(&:invoke)
end

namespace :build do
  supportedPlatforms.product(configurations).each do |platform, configuration|
    XCJobs::Build.new("#{platform}:#{configuration.downcase}") do |t|
      t.project = 'KeychainAccess'
      t.scheme = 'KeychainAccess'
      t.sdk = platform
      t.configuration = configuration
      t.build_dir = 'build'
      t.hide_shell_script_environment = true
      t.formatter = 'xcpretty -c'
      if ENV['CI']
        t.add_build_setting('CODE_SIGN_IDENTITY', '')
        t.add_build_setting('CODE_SIGNING_REQUIRED', 'NO')
      end
      if xcode_version.start_with?('11')
        t.add_build_setting('SWIFT_VERSION', '5.1')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 11,OS=13.0')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch Series 4 - 44mm,OS=6.0')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 4K,OS=13.0')
        end
      elsif xcode_version.start_with?('10.3')
        t.add_build_setting('SWIFT_VERSION', '5.0')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 7,OS=12.0')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch Series 4 - 44mm,OS=5.0')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 4K,OS=12.0')
        end
      elsif xcode_version.start_with?('10')
        t.add_build_setting('SWIFT_VERSION', '4.2')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 7,OS=12.0')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch Series 4 - 44mm,OS=5.0')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 4K,OS=12.0')
        end
      elsif xcode_version.start_with?('9.4')
        t.add_build_setting('SWIFT_VERSION', '4.1')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 7,OS=11.4')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch Series 3 - 42mm,OS=4.3')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 4K,OS=11.4')
        end
      elsif xcode_version.start_with?('9.3')
        t.add_build_setting('SWIFT_VERSION', '4.1')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 7,OS=11.3')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch - 42mm,OS=4.3')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 4K,OS=11.3')
        end
      elsif xcode_version.start_with?('9.2')
        t.add_build_setting('SWIFT_VERSION', '4.0')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 7,OS=11.2')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch - 42mm,OS=4.2')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 4K,OS=11.2')
        end
      elsif xcode_version.start_with?('9.1')
        t.add_build_setting('SWIFT_VERSION', '4.0')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 7,OS=11.1')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch - 42mm,OS=4.1')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 4K,OS=11.1')
        end
      elsif xcode_version.start_with?('9')
        t.add_build_setting('SWIFT_VERSION', '4.0')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 7,OS=11.0')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch - 42mm,OS=4.0')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 1080p,OS=11.0')
        end
      else
        t.add_build_setting('SWIFT_VERSION', '3.0')
        if platform == 'iphonesimulator'
          t.add_destination('name=iPhone 7,OS=10.3.1')
        elsif platform == 'watchsimulator'
          t.add_destination('name=Apple Watch - 42mm,OS=3.2')
        elsif platform == 'appletvsimulator'
          t.add_destination('name=Apple TV 1080p,OS=10.0')
        end
      end
    end
  end

  task :carthage do
    sh %[echo 'github \"kishikawakatsumi/KeychainAccess\"' > Cartfile]
    if xcode_version.start_with?('11')
      sh %[echo SWIFT_VERSION=\"5.1\" > swift.xcconfig]
    elsif xcode_version.start_with?('10.3')
      sh %[echo SWIFT_VERSION=\"5.0\" > swift.xcconfig]
    elsif xcode_version.start_with?('10')
      sh %[echo SWIFT_VERSION=\"4.2\" > swift.xcconfig]
    elsif xcode_version.start_with?('9.4')
      sh %[echo SWIFT_VERSION=\"4.1\" > swift.xcconfig]
    elsif xcode_version.start_with?('9.3')
      sh %[echo SWIFT_VERSION=\"4.1\" > swift.xcconfig]
    elsif xcode_version.start_with?('9')
      sh %[echo SWIFT_VERSION=\"4.0\" > swift.xcconfig]
    else
      sh %[echo SWIFT_VERSION=\"3.0\" > swift.xcconfig]
    end
    sh %[XCODE_XCCONFIG_FILE=`pwd`/swift.xcconfig carthage update --no-use-binaries]
    sh %[find . -name '*.bcsymbolmap' | xargs grep swiftlang]
  end
end

namespace :test do
  supportedPlatforms
    .select { |platform| platform == 'macosx' || platform == 'iphonesimulator' || platform == 'appletvsimulator' }
    .each do |platform|
      task platform do |t|
        configurations.each do |configuration|
          destinations(platform: platform)
            .map { |destination| Rake::Task["test:#{platform}:#{configuration.downcase}:#{destination}"] }
            .map(&:invoke)
        end
      end
    end
end

namespace :test do
  supportedPlatforms
    .select { |platform| platform == 'macosx' || platform == 'iphonesimulator' || platform == 'appletvsimulator' }
    .product(configurations)
    .each do |platform, configuration|
      destinations(platform: platform).each do |destination|
        XCJobs::Test.new("#{platform}:#{configuration.downcase}:#{destination}") do |t|
          t.project = 'KeychainAccess'
          t.scheme = 'KeychainAccess'
          t.sdk = platform
          t.configuration = configuration
          t.add_destination(destination)
          t.coverage = true
          t.build_dir = 'build'
          t.hide_shell_script_environment = true
          if xcode_version.start_with?('11')
            t.add_build_setting('SWIFT_VERSION', '5.1')
          elsif xcode_version.start_with?('10.3')
            t.add_build_setting('SWIFT_VERSION', '5.0')
          elsif xcode_version.start_with?('10')
            t.add_build_setting('SWIFT_VERSION', '4.2')
          elsif xcode_version.start_with?('9.4')
            t.add_build_setting('SWIFT_VERSION', '4.1')
          elsif xcode_version.start_with?('9.3')
            t.add_build_setting('SWIFT_VERSION', '4.1')
          elsif xcode_version.start_with?('9')
            t.add_build_setting('SWIFT_VERSION', '4.0')
          else
            t.add_build_setting('SWIFT_VERSION', '3.0')
          end
          t.after_action do
            build_coverage_reports()
            puts `curl -L https://codecov.io/bash | bash -s -- -f 'coverage.txt'`
          end
        end
      end
    end
end

def build_coverage_reports()
  project_name = 'KeychainAccess'
  profdata = Dir.glob(File.join('build', '/**/Coverage.profdata')).first
  Dir.glob(File.join('build', "/**/#{project_name}")) do |target|
    output = `xcrun llvm-cov report -instr-profile "#{profdata}" "#{target}" -arch=x86_64`
    if $?.success?
      puts output
      `xcrun llvm-cov show -instr-profile "#{profdata}" "#{target}" -arch=x86_64 -use-color=0 > coverage.txt`
      break
    end
  end
end
